import re
from typing import Any, List, Optional

from paramiko import AuthenticationException, AutoAddPolicy, SSHClient

from app.bot.services.loggers import logger
from app.database.models import Proxy, Server


class RemoteClient:
    """Client to interact with a remote host via SSH"""

    def __init__(
        self,
        host: str,
        port: int,
        user: str,
        password: str,
    ):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.client = None

    @property
    def connection(self):
        """Open SSH connection to remote host."""
        try:
            client = SSHClient()
            client.load_system_host_keys()
            client.set_missing_host_key_policy(AutoAddPolicy())
            client.connect(
                self.host,
                port=self.port,
                username=self.user,
                password=self.password,
                look_for_keys=False,
                # key_filename=self.ssh_key_filepath,
                timeout=5000,
            )
            return client
        except AuthenticationException as e:
            logger.error(
                f"AuthenticationException occurred; did you remember to generate an SSH key? {e}"
            )
        except Exception as e:
            logger.error(f"Unexpected error occurred while connecting to host: {e}")

    @staticmethod
    def read_file(conn: SSHClient, filepath: str) -> str | bool:
        """
        Read file from remote host.
        :param str filepath: Path to file hosted on remote server to fetch.
        """

        with conn.open_sftp() as sftp:
            remote_file = sftp.open(filepath)
            try:
                content = remote_file.read()
            except OSError:
                return False

        return content.decode("utf-8")

    @staticmethod
    def write_file(conn: SSHClient, filepath: str, content: str) -> bool:
        """
        Write remote file.
        :param str filepath: Path to file hosted on remote server to fetch.
        :param str content: Content of new file
        """

        with conn.open_sftp() as sftp:
            remote_file = sftp.file(filepath, "w")
            try:
                remote_file.write(content)
            except OSError as e:
                logger.exception(e)
                return False
            except Exception as e:
                logger.exception(e)
                return False

        return True


def get_proxies_from_config(
    server: Server,
    config_path: Optional[str] = "/usr/local/3proxy/3proxy.cfg",
) -> list[dict[str, str | Any]]:
    """
    Importing proxies from 3proxy.cfg
    :param Server server: Server instance
    :param Optional[str] config_path: Path to 3proxy.cfg
    """
    proxy_list = []

    client = RemoteClient(
        server.ip_address,
        port=server.ssh_port,
        user=server.login,
        password=server.password,
    )

    with client.connection as conn:
        config_content = client.read_file(conn, config_path)

    for proxy in re.findall("#*auth\ \w[\w\W]*?flush", config_content):
        try:
            login = re.findall("users ([^:]+)", proxy)[0].strip()
            password = re.findall("CL:([^ ]+)allow", proxy)[0].strip()
        except IndexError:
            login = ""
            password = ""
        port = re.findall("-p(\d+)", proxy)[0]
        if not len(port) <= 3 and login != "" and password != "":
            proxy_list.append(
                {
                    "login": login,
                    "password": password,
                    "port": port,
                }
            )

    return proxy_list
